﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using GT.Net;
using System.Timers;
using System.Net;
using System.Windows.Threading;

namespace GroupChChess
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {

        private Point mouseClick;

        private double canvasLeft;

        private double canvasTop;

        private delegate void VoidDelegate();

        public Window1()
        {

            InitializeComponent();

            Start();

            initiate();

        }


        private void initiate()
        {
            foreach (Image img in this.myCanvas.Children)
            {

                try
                {
                    
                    img.PreviewMouseDown += new MouseButtonEventHandler(piece_MouseDown);

                    img.PreviewMouseMove += new MouseEventHandler(piece_MouseMove);

                    img.PreviewMouseUp += new MouseButtonEventHandler(piece_MouseUp);

                    img.TextInput += new TextCompositionEventHandler(piece_TextInput);

                    img.LostMouseCapture += new MouseEventHandler(piece_LostMouseCapture);

                }

                catch (Exception e)
                {
                    MessageBox.Show(e.Message);
                }


            }
        }

        void piece_LostMouseCapture(object sender, MouseEventArgs e)
        {

            ((Image)sender).ReleaseMouseCapture();

        }

        void piece_TextInput(object sender, TextCompositionEventArgs e)
        {

            ((Image)sender).ReleaseMouseCapture();

        }

        void piece_MouseUp(object sender, MouseButtonEventArgs e)
        {

            ((Image)sender).ReleaseMouseCapture();

        }

        /*
         * detect captured piece and send message
         */
        void piece_MouseMove(object sender, MouseEventArgs e)
        {

            if (((Image)sender).IsMouseCaptured)
            {

                Point mouseCurrent = e.GetPosition(null);

                // minus 32.5 (half the width of a piece)
                double Left = mouseCurrent.X - 32.5 - canvasLeft;

                double Top = mouseCurrent.Y - 32.5 - canvasTop;

                ((Image)sender).SetValue(Canvas.LeftProperty, canvasLeft + Left);

                ((Image)sender).SetValue(Canvas.TopProperty, canvasTop + Top);

                canvasLeft = Canvas.GetLeft(((Image)sender));

                canvasTop = Canvas.GetTop(((Image)sender));

                if (!isConnected)
                    return;

                objectChannel.Send(new CursorUpdateMessage(((Image)sender).Name, mouseCurrent));

            }

        }

        private void Process(CursorUpdateMessage message)
        {
            //lock (myCanvas.Children);
            //System.Windows.Controls.UIElementCollection
            Dispatcher.Invoke(DispatcherPriority.Normal,
                  new Action(
                      delegate()
                      {
                          foreach (Image img in this.myCanvas.Children)
                          {
                              if (img.Name.Equals(message.PieceName))
                              {
                                  // minus 32.5 (half the width of a piece)
                                  double Left = message.Location.X - 32.5 - canvasLeft;

                                  double Top = message.Location.Y - 32.5 - canvasTop;

                                  img.SetValue(Canvas.LeftProperty, canvasLeft + Left);

                                  img.SetValue(Canvas.TopProperty, canvasTop + Top);

                                  canvasLeft = Canvas.GetLeft(img);

                                  canvasTop = Canvas.GetTop((img));
                              }
                          }
                      }
                  )
            );

        }

        void piece_MouseDown(object sender, MouseButtonEventArgs e)
        {

            mouseClick = e.GetPosition(null);

            canvasLeft = Canvas.GetLeft(((Image)sender));

            canvasTop = Canvas.GetTop(((Image)sender));

            ((Image)sender).CaptureMouse();

        }

        IObjectChannel objectChannel;
        Client client;
        Timer updateTimer;
        const double UPDATE_INTERVAL_ms = 1000 / 30.0;
        const string PORT_NUMBER = "9999";
        const byte CHANNEL_ID = (Byte)0;
        bool isConnected = false;

    
        /// <summary>
        /// Connects to the address displayed in txtServerAddress
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Start()
        {
            if (isConnected)
                return;

            client = new Client();

            try
            {
                client.Start();
                objectChannel = client.OpenObjectChannel("127.0.0.1", PORT_NUMBER, CHANNEL_ID, ChannelDeliveryRequirements.CommandsLike);
                isConnected = true;
                if (objectChannel != null)
                    MessageBox.Show("Game is connected to server");
            }
            catch (Exception ex)
            {
                MessageBox.Show("Could not connect to given address. \nProblem:\n\t" + ex.Message);
            }

            /* Start an update timer.
             * Notes:
             * -    Timer is required to update the client and retrieve messages.
             */
            updateTimer = new Timer(UPDATE_INTERVAL_ms);
            updateTimer.Elapsed += new ElapsedEventHandler(updateTimer_Elapsed);
            updateTimer.Start();

        }



        /// <summary>
        /// Updates the client and receives messages.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void updateTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            /*If we're not connected to any repeater, then simply exit.*/
            if (!isConnected)
                return;

            //Update the client, receiving messages.
            client.Update();

            /* While messages exist on the message queue, process them.
             * Notes:
             * -    If you want to handle all mesasges in order, use OLDEST_MESSAGE = 0.
             * -    If you want to handle newest messages first, use OLDEST_MESSAGE = (queue's size-1).
             */
            const int OLDEST_MESSAGE = 0;
            object message;
            while ((message = objectChannel.DequeueMessage(OLDEST_MESSAGE)) != null)
            {
                /* Determine the received message and process it.
                 * How you process the message is up to you. Although I don't use it here, the Command pattern is very handy.
                 */
                if (message is CursorUpdateMessage)
                {
                    Process((CursorUpdateMessage)message);
                }
            }

            /*Refresh the window for drawing purposes. You can do this wherever it is appropriate.*/
            //Delegate d = new VoidDelegate(drawer.InvalidateVisual);
            //Dispatcher.BeginInvoke(d, System.Windows.Threading.DispatcherPriority.Render, null);
        }


    }



}
